home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / program / misc / fpl-v13.lha / fpl / src / hash.c < prev    next >
C/C++ Source or Header  |  1995-08-22  |  32KB  |  1,163 lines

  1. /******************************************************************************
  2.  *                   FREXX PROGRAMMING LANGUAGE                  *
  3.  ******************************************************************************
  4.  
  5.  hash.c
  6.  
  7.  Functions for FPL hash tables and sorting!
  8.  
  9.  *****************************************************************************/
  10.  
  11. /************************************************************************
  12.  *                                                                      *
  13.  * fpl.library - A shared library interpreting script langauge.         *
  14.  * Copyright (C) 1992-1994 FrexxWare                                    *
  15.  * Author: Daniel Stenberg                                              *
  16.  *                                                                      *
  17.  * This program is free software; you may redistribute for non          *
  18.  * commercial purposes only. Commercial programs must have a written    *
  19.  * permission from the author to use FPL. FPL is *NOT* public domain!   *
  20.  * Any provided source code is only for reference and for assurance     *
  21.  * that users should be able to compile FPL on any operating system     *
  22.  * he/she wants to use it in!                                           *
  23.  *                                                                      *
  24.  * You may not change, resource, patch files or in any way reverse      *
  25.  * engineer anything in the FPL package.                                *
  26.  *                                                                      *
  27.  * This program is distributed in the hope that it will be useful,      *
  28.  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
  29.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
  30.  *                                                                      *
  31.  * Daniel Stenberg                                                      *
  32.  * Ankdammsgatan 36, 4tr                                                *
  33.  * S-171 43 Solna                                                       *
  34.  * Sweden                                                               *
  35.  *                                                                      *
  36.  * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
  37.  *                                                                      *
  38.  ************************************************************************/
  39.  
  40. #ifdef AMIGA
  41. #include <exec/types.h>
  42. #include <proto/exec.h>
  43. #include <dos.h>
  44. #else
  45. #include <stdio.h>
  46. #endif
  47. #include "script.h"
  48. #include "debug.h"
  49. #include <limits.h>
  50.  
  51. #ifdef DEBUG
  52. #include <stdio.h>
  53. #endif
  54.  
  55. static ReturnCode REGARGS AddIdentifier(struct Data *, struct Identifier *);
  56. static ReturnCode INLINE InitHash(struct Data *);
  57. static unsigned long INLINE Gethash(uchar *);
  58. static void * INLINE Init(struct Data *, long ASM (*)(AREG(0) void *), unsigned long *);
  59. static ReturnCode REGARGS SetTags(struct Data *, unsigned long *);
  60. static ReturnCode INLINE Hijack(struct Data *, struct Identifier *);
  61.  
  62.  
  63. ReturnCode REGARGS
  64.     RenameIdentifier(struct Data *scr,
  65.              struct Identifier *ident, /* existing identifier */
  66.              uchar *newname)           /* new name */
  67. {
  68.     ReturnCode ret;
  69.     struct Identifier *nident;
  70.     ret = GetIdentifier(scr, newname, &nident);
  71.     if(ret != FPLERR_IDENTIFIER_NOT_FOUND) {
  72.       return FPLERR_IDENTIFIER_USED; /* !!! */
  73.     }
  74.  
  75.     if(ident->flags&FPL_KEYWORD) {
  76.       /*
  77.        * Nonononono... we have to draw the limit somewhere!!!
  78.        * We really can't allow someone changing the keywords!!!
  79.        */
  80.       return FPLERR_IDENTIFIER_USED;
  81.     }
  82.     /*
  83.      * Let's take the old one out of its chains!
  84.      */
  85.     if(ident->prev) {
  86.       /* If there is a previous member */
  87.       ident->prev->next=ident->next;
  88.     }
  89.     else {
  90.       /* if this was the first in the list */
  91.       scr->hash[ident->hash%scr->hash_size]=ident->next;
  92.     }
  93.     if(ident->next) {
  94.       ident->next->prev=ident->prev;
  95.     }
  96.     if(ident->flags&(FPL_INTERNAL_FUNCTION|FPL_KEYWORD|FPL_EXTERNAL_FUNCTION)) {
  97.       if(ident->flags&FPL_DEALLOC_NAME_ANYWAY) {
  98.         /* Oh well, this has already been renamed once! */
  99.         FREE_KIND(ident->name);
  100.       }
  101.       else
  102.         ident->flags |= FPL_DEALLOC_NAME_ANYWAY;
  103.         /* this have to be known since this kind of functions regularly uses
  104.            names in the user-area which never get freed by us! */
  105.     }
  106.     else {
  107.       FREE_KIND(ident->name);
  108.     }
  109.     STRDUPA(ident->name, newname);
  110.     CALL( AddIdentifier(scr, ident));
  111.     return ret;
  112. }
  113.  
  114. #ifndef AMIGA /* if not using SAS/C on Amiga */
  115.  
  116. #ifdef VARARG_FUNCTIONS
  117. long fplAddFunctionTags(void *anchor, uchar *name, long ID, uchar rtrn,
  118.                         uchar *format, ...)
  119. {
  120.   va_list tags;
  121.   long ret;
  122.   va_start(tags, format); /* get parameter list */
  123.   ret = fplAddFunction(anchor, name, ID, rtrn, format, (unsigned long *)tags);
  124.   va_end(tags)
  125.   return ret;
  126. }
  127. #else
  128. long fplAddFunctionTags(void *anchor, uchar *name, long ID, uchar rtrn,
  129.                         uchar *format, unsigned long tags, ...)
  130. {
  131.   return(fplAddFunction(anchor, name, ID, rtrn, format, &tags));
  132. }
  133. #endif
  134.  
  135. #endif
  136.  
  137. /**********************************************************************
  138.  *
  139.  * int fplAddFunction();
  140.  *
  141.  * User frontend to AddIdentifier().
  142.  *
  143.  *****/
  144.  
  145. ReturnCode PREFIX
  146.   fplAddFunction(AREG(0) struct Data *scr,      /* pointer to struct Data */
  147.          AREG(1) uchar *name,     /* name of function */
  148.          DREG(0) long ID,     /* function ID */
  149.          DREG(1) uchar rtrn,      /* return type */
  150.          AREG(2) uchar *format,   /* format string */
  151.          AREG(3) unsigned long *tags) /* taglist pointer */
  152. {
  153.   ReturnCode ret;
  154.   struct Identifier *ident;
  155. #ifdef DEBUGMAIL
  156.   DebugMail(scr, MAIL_FUNCTION, 500, "fplAddFunction");
  157. #endif
  158.   if(!scr)
  159.     return(FPLERR_ILLEGAL_ANCHOR);
  160.  
  161.   ident=MALLOCA(sizeof(struct Identifier));
  162.   if(!ident)
  163.     return(FPLERR_OUT_OF_MEMORY);
  164.  
  165.   memset(&ident->data.external, 0, sizeof(struct ExternalFunction));
  166.   while(tags && *tags) {
  167.     switch(*tags++) {
  168.     case FPLTAG_USERDATA:
  169.       ident->data.external.data=(void *)*tags;
  170.       break;
  171.     case FPLTAG_FUNCTION:
  172.       ident->data.external.func=(long (*)(void *))*tags;
  173.       break;
  174.     }
  175.     tags++; /* next! */
  176.   }
  177.  
  178.   ident->name = name;
  179.   ident->data.external.ID = ID;
  180.   ident->data.external.ret = rtrn;
  181.   ident->data.external.format = format;
  182.   ident->flags = FPL_EXTERNAL_FUNCTION|FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL;
  183.   ident->file = "<user>"; /* User added! */
  184.   ident->func = NULL; /* everywhere! */
  185.   ident->level = 0;
  186.  
  187.   CALL(AddIdentifier(scr, ident));
  188.   return(FPL_OK);
  189. }
  190.  
  191. /**********************************************************************
  192.  *
  193.  * int fplDelFunction();
  194.  *
  195.  * User frontend to DelIdentifier().
  196.  *
  197.  ******/
  198.  
  199. ReturnCode PREFIX fplDelFunction(AREG(0) struct Data *scr,
  200.                  AREG(1) uchar *name)
  201. {
  202.   ReturnCode ret;
  203. #ifdef DEBUGMAIL
  204.   DebugMail(scr, MAIL_FUNCTION, 500, "fplDelFunction");
  205. #endif
  206.   if(!scr)
  207.     return(FPLERR_ILLEGAL_ANCHOR);
  208.   CALL(DelIdentifier(scr, name, NULL));
  209.   return(FPL_OK);
  210. }
  211.  
  212.  
  213. /**********************************************************************
  214.  *
  215.  * int AddVar();
  216.  *
  217.  * Frontend to the AddIdentifier function.
  218.  *
  219.  * This routine adds a member to the linked list of local variable names.
  220.  * That list exists to enable easy and fast removal of local variables
  221.  * when leaving a block within which local variables has been declared!
  222.  *
  223.  * Make sure that the name member data is static as long we need this list
  224.  * cause this routine doesn't copy that name, simply points to it!
  225.  *
  226.  *****/
  227.  
  228.  
  229. ReturnCode REGARGS
  230. AddVar(struct Data *scr, /* pointer to struct Data */
  231.        struct Identifier *ident,/* identifier struct pointer */
  232.        struct Local **local)
  233. {
  234.   ReturnCode ret;
  235.   struct Local *temp;
  236.   if(ret=AddIdentifier(scr, ident))
  237.     ;
  238.   else {
  239.     GETMEM(temp, sizeof(struct Local));  
  240.     temp->next=*local;
  241.     temp->ident=ident;
  242.     *local=temp;
  243.   }
  244.   return(ret);
  245. }
  246.  
  247. /**********************************************************************
  248.  *
  249.  * AddLevel();
  250.  *
  251.  * This function adds a NULL-name in the local symbol list to visualize
  252.  * the beginning of a new variable level!
  253.  *
  254.  *******/
  255.  
  256. ReturnCode REGARGS
  257. AddLevel(struct Data *scr)
  258. {
  259.   struct Local *temp;
  260.   GETMEM(temp, sizeof(struct Local));  
  261.   temp->next=scr->locals;
  262.   temp->ident=NULL;
  263.   scr->locals=temp;
  264.   return(FPL_OK);
  265. }
  266.  
  267.  
  268. /**********************************************************************
  269.  *
  270.  * int DelLocalVar()
  271.  *
  272.  * This routine deletes all members to the linked list of local variable
  273.  * names. Call this routine every time you leave a local level. Deletes
  274.  * all variables and the following NULL name!
  275.  *
  276.  *****/
  277.  
  278. ReturnCode REGARGS
  279. DelLocalVar(struct Data *scr,
  280.             struct Local **local)
  281. {
  282.   /* This removes only all listed symbols! */
  283.   struct Identifier *ident;
  284.   while(*local) {
  285.     struct Local *temp=(*local)->next;
  286.     ident=(*local)->ident;
  287.     FREE(*local);
  288.     *local=temp;
  289.     if(ident)
  290.       DelIdentifier(scr, NULL, ident); /* delete it for real */
  291.     else
  292.       break;
  293.   }
  294.   return(FPL_OK);
  295. }
  296.  
  297.  
  298. /**********************************************************************
  299.  *
  300.  * int AddIdentifier()
  301.  *
  302.  * This function adds the function to the hash table according to all
  303.  * parameters.
  304.  *
  305.  * If the hash member of the Data structure is NULL, the hash table
  306.  * will be inited. No not init the hash list if you don't have to cause
  307.  * that sure is a peep hole in the performance...
  308.  *
  309.  *******/
  310.  
  311. static ReturnCode REGARGS
  312. AddIdentifier(struct Data *scr,
  313.               struct Identifier *ident)
  314. {
  315.   unsigned long hash;       /* hash number of the identifier */
  316.   struct Identifier **add;  /* where to store the pointer to this identifier */
  317.   struct Identifier *prev=NULL; /* pointer to previous hash structure */
  318.   struct Identifier *next;  /* pointer to next hash structure */
  319.   ReturnCode ret;
  320.   hash=Gethash(ident->name);
  321.   
  322.   add=(struct Identifier **)&scr->hash[hash % scr->hash_size];
  323.   while(*add) {
  324.     if((*add)->hash==hash) {
  325.       /* they were identical */
  326.       if(ident->flags&FPL_FUNCTION &&
  327.      !strcmp((*add)->name, ident->name) &&
  328. /*
  329.   PREV STOOPID WAY:
  330.      (!ident->file || !strcmp(ident->file, (*add)->file))) { */
  331.  
  332.      (ident->flags&FPL_EXPORT_SYMBOL || !strcmp(ident->file, (*add)->file))) {
  333.     /* if it's already there, fail!!! */
  334.     return FPLERR_IDENTIFIER_USED;
  335.       } else
  336.     /* add it here! */
  337.     break; 
  338.     } else if((*add)->hash>hash) {
  339.       /* continue search for a place to insert */
  340.       /* 'add' now points to the pointer */
  341.       prev=(*add);
  342.       add=(struct Identifier **)&((*add)->next);
  343.     } else {
  344.       /* insert it here! */
  345.       prev=(*add)->prev;
  346.       break;
  347.     }
  348.   }
  349.  
  350.   next=(*add);
  351.   *add=ident;
  352.   (*add)->hash=hash;
  353.   (*add)->prev=prev;
  354.   (*add)->next=next;
  355.   if(next)
  356.     next->prev=ident;
  357.   return(FPL_OK);
  358. }
  359.  
  360. /**********************************************************************
  361.  *
  362.  * int GetIdentifier();
  363.  *
  364.  * Sets the pointer to the Identifier structure to which the name
  365.  * fits, in the third argument.
  366.  *
  367.  *****/
  368.  
  369. #ifdef DEBUG
  370. int hashed=0;
  371. int max_hashed=0;
  372. #endif
  373.  
  374. ReturnCode REGARGS
  375. GetIdentifier(struct Data *scr,
  376.               uchar *name,
  377.           struct Identifier **ident)
  378. {
  379.   ReturnCode ret;
  380.   struct Identifier *get;
  381.   unsigned long hash=Gethash(name);
  382.   get=scr->hash[hash%scr->hash_size];
  383. #ifdef DEBUG
  384.   hashed=0;
  385. #endif
  386.  
  387.   while(get) {
  388.     if(
  389.  
  390.        (get->hash==hash) && 
  391.        /* identical hash value! */
  392.  
  393.        !strcmp(get->name, name) &&
  394.        /* identical name! */
  395.  
  396.        (get->flags&(FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL) ||
  397.         (get->func==scr->func && get->level<=scr->varlevel)) &&
  398.        /* If not global, declared under the *same* function, in this or
  399.       a lower level! */
  400.  
  401.        (get->flags&FPL_EXPORT_SYMBOL || !strcmp(get->file, scr->prog->name))
  402.        /* If not cross-file, the same file! */
  403.  
  404.        ) {
  405.  
  406.       /* this is it! */
  407.       *ident=get;
  408. #ifdef DEBUG
  409.       if(hashed>max_hashed)
  410.     max_hashed=hashed;
  411. #endif
  412.       if(get->flags&FPL_EXTERNAL_VARIABLE) {
  413.         CALL(Hijack(scr, get));
  414.       }
  415.       else if(scr->flags&FPLDATA_ISOLATE && get->flags&FPL_EXPORT_SYMBOL) {
  416.         /*
  417.          * Isolated and exported symbol... really?
  418.          */
  419.         if((get->flags&(FPL_FUNCTION|FPL_KEYWORD) == FPL_INSIDE_FUNCTION) ||
  420.            get->flags&FPL_VARIABLE) {
  421.           /*
  422.            * Nope, this symbol shouldn't get returned!
  423.            */
  424.           break;
  425.         }
  426.       }
  427. #ifdef DEBUGMAIL
  428.       DebugMail(scr, MAIL_IDENTIFIER_ACCESS, 0, get);
  429. #endif
  430.       return FPL_OK;
  431.     } else if(get->hash<hash)
  432.       /* we've been searching through all possible alternatives! */
  433.       break;
  434. #ifdef DEBUG
  435.     hashed++;
  436. #endif
  437.     get=get->next;
  438.   }
  439.   *ident=NULL;
  440.   return FPLERR_IDENTIFIER_NOT_FOUND;
  441. }
  442.  
  443.  
  444. #ifndef AMIGA /* if not using SAS/C on Amiga */
  445.  
  446. #ifdef VARARG_FUNCTIONS
  447. long fplAddVariableTags(void *anchor, uchar *name, long ID, uchar type,
  448.                         void *defvalue, ...)
  449. {
  450.   va_list tags;
  451.   long ret;
  452.   va_start(tags, format); /* get parameter list */
  453.   ret = fplAddVariable(anchor, name, ID, type, defvalue, (unsigned long *)tags);
  454.   va_end(tags)
  455.   return ret;
  456. }
  457. #else
  458. long fplAddVariableTags(void *anchor, uchar *name, long ID, uchar type,
  459.                         void *defvalue, unsigned long tags, ...)
  460. {
  461.   return fplAddVariable(anchor, name, ID, type, defvalue, &tags);
  462. }
  463. #endif
  464.  
  465. #endif
  466.  
  467. /**********************************************************************
  468.  *
  469.  * int fplAddVariable();
  470.  *
  471.  * User frontend to AddIdentifier(). New in version 10!
  472.  *
  473.  *****/
  474.  
  475. ReturnCode PREFIX
  476.   fplAddVariable(AREG(0) struct Data *scr, /* pointer to struct Data */
  477.          AREG(1) uchar *name,       /* name of variable */
  478.          DREG(0) long ID,       /* variable ID */
  479.          DREG(1) uchar type,        /* variable type */
  480.                  AREG(2) void *defvalue,   /* default value */
  481.          AREG(3) unsigned long *tags) /* taglist pointer */
  482. {
  483.   ReturnCode ret;
  484.   struct Identifier *ident;
  485. #ifdef DEBUGMAIL
  486.   DebugMail(scr, MAIL_FUNCTION, 500, "fplAddVariable");
  487. #endif
  488.   if(!scr)
  489.     return(FPLERR_ILLEGAL_ANCHOR);
  490.  
  491.   GETMEMA(ident, sizeof(struct Identifier));
  492.  
  493.   memset(&ident->data.variable, 0, sizeof(struct fplVariable));
  494.  
  495.   ident->name = name;
  496.   ident->data.variable.ID = ID;
  497.   ident->flags = FPL_EXTERNAL_VARIABLE|FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL|
  498.     (type == FPL_STRARG? FPL_STRING_VARIABLE:FPL_INT_VARIABLE)|
  499.       FPL_READONLY;
  500.   if(type == FPL_INTARG) {
  501.     GETMEM(ident->data.variable.var.val32, sizeof(long));
  502.     ident->data.variable.var.val32[0] = (long) defvalue;
  503.   }
  504.   else
  505.     if(defvalue) {
  506.       register long len = (long)strlen((uchar *)defvalue);
  507.       if(len) {
  508.         GETMEM(ident->data.variable.var.str, sizeof(struct fplStr *));
  509.         GETMEM(ident->data.variable.var.str[0], len + sizeof(struct fplStr));
  510.         ident->data.variable.var.str[0]->len = len;
  511.         ident->data.variable.var.str[0]->alloc = len;
  512.         memcpy(ident->data.variable.var.str[0]->string, defvalue,
  513.                len);
  514.         ident->data.variable.var.str[0]->string[len] = '\0'; /* Z-terminate */
  515.       }
  516.     }
  517.   ident->file = "<user>"; /* Used added! */
  518.   ident->func = NULL; /* everywhere! */
  519.   ident->level = 0;
  520.  
  521.   CALL(AddIdentifier(scr, ident));
  522.   return(FPL_OK);
  523. }
  524.  
  525. /*************************************************************************
  526.  *
  527.  * Hijack();
  528.  *
  529.  * This function gets called whenever an external variable has been selected
  530.  * by GetIdentifier().
  531.  *
  532.  ******/
  533.  
  534. static ReturnCode INLINE Hijack(struct Data *scr, struct Identifier *ident)
  535. {
  536.   struct fplArgument pass;
  537.   struct fplMsg *msg;
  538.   ReturnCode ret;
  539.  
  540.   memset(&pass, 0, sizeof(struct fplArgument));
  541.   pass.argc=0;
  542.   pass.name=ident->name;
  543.   pass.ID=ident->data.variable.ID;
  544.   pass.key=scr;
  545.  
  546.   pass.variable = (void *)
  547.     (ident->flags&FPL_STRING_VARIABLE?
  548.      (ident->data.variable.var.str &&ident->data.variable.var.str[0]?
  549.       ident->data.variable.var.str[0]->string:""):
  550.      (void *)ident->data.variable.var.val32[0]);
  551.  
  552.   CALL(InterfaceCall(scr, &pass, scr->function));
  553.   if(ident->flags&FPL_INT_VARIABLE) {
  554.     /*
  555.      * Integer variable!
  556.      */
  557.     CALL(GetMessage(scr, FPLMSG_RETURN, &msg));
  558.     if(msg && msg->flags&FPLMSG_FLG_INT) {
  559.       ident->data.variable.var.val32[0]=(long)msg->message[0];
  560.       CALL(DeleteMessage(scr, msg));
  561.     }
  562.   } else {
  563.     /*
  564.      * String variable!
  565.      */
  566.     CALL(GetMessage(scr, FPLMSG_RETURN, &msg));
  567.     if(msg && msg->flags&FPLMSG_FLG_STRING) {
  568.       if(!ident->data.variable.var.str) {
  569.     GETMEMA(ident->data.variable.var.str, sizeof(struct fplStr *));
  570.       }
  571.       else if(ident->data.variable.var.str[0]) {
  572.     FREEA(ident->data.variable.var.str[0]);
  573.       }
  574.       ident->data.variable.var.str[0]=(struct fplStr *)msg->message[0];
  575.       /*
  576.        * Make the string to be static always!
  577.        */
  578.       SwapMem(scr, ident->data.variable.var.str[0], MALLOC_STATIC);
  579.       DeleteMessage(scr, msg);
  580.     }
  581.   }
  582.   return(FPL_OK);
  583. }
  584.  
  585. /**********************************************************************
  586.  *
  587.  * int InitHash()
  588.  *
  589.  * Initialize the hash table. Simple and quick!
  590.  *
  591.  *****/
  592.  
  593. struct ShitData {
  594.   uchar *name;
  595.   long ID;
  596.   uchar ret;
  597.   uchar *format;
  598. };
  599.  
  600. struct MoreShitData {
  601.   uchar *name;
  602.   long ID;
  603.   long flags;
  604. };
  605.  
  606. static ReturnCode INLINE InitHash(struct Data *scr)
  607. {
  608.   ReturnCode ret;
  609.   static struct ShitData internal_functions[]={
  610.     {"abs",        FNC_ABS,    'I', "I"},
  611.     {"atoi",        FNC_ATOI,    'I', "S"},
  612.     {"closelib",    FNC_CLOSELIB,    'I', "S"},  /* amiga only */
  613.     {"debug",        FNC_DEBUG,    'I', "i"},
  614.     {"eval",        FNC_EVAL,    'I', "S"},
  615.     {"exists",          FNC_EXISTS,     'I', "Si"},
  616.     {"interpret",    FNC_INTERPRET,    'I', "S"},
  617.     {"itoa",        FNC_ITOA,    'S', "I"},
  618.     {"itoc",        FNC_ITOC,    'S', "I"},
  619.     {"joinstr",        FNC_JOINSTR,    'S', "s>"},
  620.     {"ltostr",        FNC_LTOSTR,    'S', "Ii"},
  621.     {"openlib",        FNC_OPENLIB,    'I', "SI"}, /* amiga only */
  622.     {"rename",        FNC_RENAME,     'I', "SS"},
  623.     {"sprintf",        FNC_SPRINTF,    'S', "Sa>"},
  624.     {"sscanf",          FNC_SSCANF,     'I', "SSa>"},
  625.     {"strcmp",        FNC_STRCMP,    'I', "SS"},
  626.     {"stricmp",        FNC_STRICMP,    'I', "SS"},
  627.     {"strlen",        FNC_STRLEN,    'I', "S"},
  628.     {"strncmp",        FNC_STRNCMP,    'I', "SSI"},
  629.     {"strnicmp",    FNC_STRNICMP,    'I', "SSI"},
  630.     {"strstr",        FNC_STRSTR,    'I', "SSi"},
  631.     {"stristr",        FNC_STRISTR,    'I', "SSi"},
  632.     {"strtol",        FNC_STRTOL,    'I', "Si"},
  633.     {"substr",        FNC_SUBSTR,    'S', "SII"},
  634.   };
  635.  
  636.   /* FPL keywords. "else" is not included (treated special). Is is
  637.      defines as KEYWORD_ELSE */
  638.  
  639.   static struct MoreShitData keywords[]={
  640.     {"auto",    CMD_AUTO,    FPL_KEYWORD_DECLARE},
  641.     {"break",    CMD_BREAK,    0},
  642.     {"case",    CMD_CASE,    0},
  643.     {"char",    CMD_INT,    FPL_KEYWORD_DECLARE|FPL_CHAR_VARIABLE},
  644.     {"const",    CMD_CONST,    FPL_KEYWORD_DECLARE},
  645.     {"continue", CMD_CONTINUE,    0},
  646.     {"default",    CMD_DEFAULT,    0},
  647.     {"do",    CMD_DO,        0},
  648.     {"double",    CMD_DOUBLE,    FPL_IGNORE},
  649.     {"enum",    CMD_ENUM,    FPL_IGNORE},
  650.     {"exit",    CMD_EXIT,    0},
  651.     {"export",    CMD_EXPORT,    FPL_KEYWORD_DECLARE},
  652.     {"float",   CMD_FLOAT,    FPL_IGNORE},
  653.     {"for",    CMD_FOR,    0},
  654.     {"if",    CMD_IF,        0},
  655.     {"int",    CMD_INT,    FPL_KEYWORD_DECLARE},
  656.     {"long",    CMD_INT,    FPL_KEYWORD_DECLARE},
  657.     {"register",CMD_REGISTER,    FPL_KEYWORD_DECLARE},
  658.     {"resize",    CMD_RESIZE,    0},
  659.     {"return",    CMD_RETURN,    0},
  660.     {"short",    CMD_INT,    FPL_KEYWORD_DECLARE|FPL_SHORT_VARIABLE},
  661.     {"signed",    CMD_SIGNED,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  662.     {"static",  CMD_STATIC,    FPL_KEYWORD_DECLARE},
  663.     {"string",    CMD_STRING,    FPL_KEYWORD_DECLARE},
  664.     {"struct",  CMD_STRUCT,    FPL_IGNORE},
  665.     {"switch",    CMD_SWITCH,    0},
  666.     {"typedef",    CMD_TYPEDEF,    0},
  667.     {"union",    CMD_UNION,    FPL_IGNORE},
  668.     {"unsigned",CMD_UNSIGNED,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  669.     {"void",    CMD_VOID,    FPL_KEYWORD_DECLARE},
  670.     {"volatile",CMD_VOLATILE,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  671.     {"while",    CMD_WHILE,    0},
  672.   };
  673.   long i;
  674.   struct Identifier *ident;
  675.   GETMEMA(scr->hash, sizeof(struct Identifier *)* scr->hash_size);
  676.  
  677.   memset((void *)scr->hash, 0, sizeof(struct Identifier *)*scr->hash_size);
  678.   /*
  679.    * The hash table initialization gives us a brilliant chance to bring up
  680.    * the execution speed even more by inserting the few internal functions
  681.    * into this same table. The functions will then act *EXACTLY* the same
  682.    * and we can shorten the code and much easier write internal functions
  683.    * that return strings...
  684.    */
  685.  
  686.   for(i=0; i<sizeof(internal_functions)/sizeof(struct ShitData);i++) {
  687.     GETMEMA(ident, sizeof(struct Identifier));
  688.     ident->name=internal_functions[i].name;
  689.     ident->data.external.ID=internal_functions[i].ID;
  690.     ident->data.external.ret=internal_functions[i].ret;
  691.     ident->data.external.format=internal_functions[i].format;
  692.     ident->flags=FPL_INTERNAL_FUNCTION|FPL_EXPORT_SYMBOL;
  693.     ident->level=0;
  694.     ident->func=NULL; /* all functions */
  695.     ident->file= "<FPL>"; /* internal */
  696.     ret=AddIdentifier(scr, ident);
  697.     if(ret)
  698.       break;
  699.   }
  700.   for(i=0; i<sizeof(keywords)/sizeof(struct MoreShitData);i++) {
  701.     GETMEMA(ident, sizeof(struct Identifier));
  702.     ident->name=keywords[i].name;
  703.     ident->data.external.ID=keywords[i].ID;  /* dirty enum work! */
  704.     ident->flags=FPL_EXPORT_SYMBOL|FPL_KEYWORD|keywords[i].flags;
  705.     ident->level=0;
  706.     ident->func=NULL;  /* all functions */
  707.     ident->file= "<FPL>";  /* internal */
  708.     ret=AddIdentifier(scr, ident);
  709.     if(ret)
  710.       break;
  711.   }
  712.   return(ret);
  713. }
  714.  
  715. /**********************************************************************
  716.  *
  717.  * int Gethash();
  718.  *
  719.  * Return the hash number for the name received as argument.
  720.  *
  721.  *****/
  722.  
  723. static unsigned long INLINE Gethash(uchar *name)
  724. {
  725.   unsigned long hash=0;
  726.   while(*name)
  727.     hash=(hash<<1)+*name+++(hash&(1<<31)?-2000000000:0);
  728.   return(hash);
  729. }
  730.  
  731. /**********************************************************************
  732.  *
  733.  * void Free();
  734.  *
  735.  * This function frees the resources used by this FPL session.
  736.  *
  737.  ***********/
  738.  
  739. void PREFIX fplFree(AREG(0) struct Data *scr)
  740. {
  741.   struct Data onstack;
  742.   long retval;
  743. #ifdef DEBUGMAIL
  744.   DebugMail(scr, MAIL_FUNCTION, 500, "fplFree");
  745. #endif
  746.   onstack=*scr; /* copy the entire struct */
  747.   scr=&onstack; /* use the `stack-struct' */
  748.   DelProgram(scr, NULL); /* remove all programs from memory, some might be
  749.                 Lock()'ed! */
  750. #ifdef AMIGA /* only amiga supports funclibs! */
  751.   CloseLib(scr, NULL, TRUE, &retval); /* force close of all funclibs */
  752. #endif
  753.   FREEALL();
  754.   FREEALLA();
  755. }
  756.  
  757. /**********************************************************************
  758.  *
  759.  * int DelIdentifier()
  760.  *
  761.  * Delete an identifier from the hash table. Specify 'name' or 'ident'.
  762.  *
  763.  ******/
  764.  
  765. ReturnCode REGARGS
  766. DelIdentifier(struct Data *scr,
  767.               uchar *name, /* only needed if 'ident' is NULL! */
  768.           struct Identifier *ident)
  769. {
  770.   ReturnCode ret=FPL_OK;
  771.   long i;
  772.   struct fplVariable *var;
  773.  
  774.   if(!ident) {
  775.     /* Get the structure pointer */
  776.     CALL(GetIdentifier(scr, name, &ident));
  777.   }
  778.   
  779.   /* Link the previous member in the list to the next member */
  780.   if(ident->prev)
  781.     /* If there is a previous member */
  782.     ident->prev->next=ident->next;
  783.   else
  784.     /* if this was the first in the list */
  785.     scr->hash[ident->hash%scr->hash_size]=ident->next;
  786.  
  787.   if(ident->next)
  788.     ident->next->prev=ident->prev;
  789.  
  790.   /*
  791.    * If it is any kind of funtion, all the data the pointers points to
  792.    * should (in the specs) be static and should therefore *NOT* be
  793.    * freed here!
  794.    *
  795.    * Notice that even internal functions are possible to remove here...
  796.    */
  797.  
  798.   if(ident->flags & FPL_VARIABLE) {
  799.     /*
  800.      * It's a variable identifier. Free some members:
  801.      */
  802.     
  803.     var=&ident->data.variable;
  804.     
  805.     if(ident->flags & FPL_REFERENCE) {
  806.       /* only keep a reference pointer! */
  807.     }
  808.     else {
  809.       if(ident->flags & FPL_STRING_VARIABLE) {
  810.     /* it's a string array! */
  811.     for(i=0; i<var->size; i++)
  812.       if(var->var.str[i]) {
  813.         FREE_KIND(var->var.str[i]);
  814.       }
  815.       }
  816.       if(var->num)
  817.     FREE_KIND(var->dims);
  818.       FREE_KIND(var->var.val);
  819.     }
  820.   } else if(ident->flags&FPL_INSIDE_FUNCTION &&
  821.             ident->data.inside.format) {
  822.     FREE_KIND(ident->data.inside.format);
  823.   }
  824.   if((ident->flags&FPL_EXTERNAL_FUNCTION)||
  825.      (ident->flags&(FPL_INTERNAL_FUNCTION|FPL_KEYWORD))) {
  826.     /* internal or external function/keyword */
  827.     if(ident->flags&FPL_DEALLOC_NAME_ANYWAY)
  828.       /* this name has been renamed into this! */
  829.       FREE_KIND(ident->name);
  830.     FREEA(ident);
  831.   } else  {
  832.     FREE_KIND(ident->name);
  833.     FREE_KIND(ident);
  834.   }
  835.   return(ret);
  836. }
  837.  
  838.  
  839. #ifndef AMIGA /* if not using SAS/C on Amiga */
  840.  
  841. #ifdef VARARG_FUNCTIONS
  842. void *fplInitTags(long (*func)(void *), ...)
  843. {
  844.   va_list tags;
  845.   void *ret;
  846.   va_start(tags, func); /* get parameter list */
  847.   ret = fplInit(func, (unsigned long *)tags);
  848.   va_end(tags)
  849.   return ret;
  850. }
  851. #else
  852. void *fplInitTags(long (*func)(void *), unsigned long tags, ...)
  853. {
  854.   return(fplInit(func, (unsigned long *)&tags));
  855. }
  856. #endif
  857.  
  858. #endif
  859.  
  860. /**********************************************************************
  861.  *
  862.  * fplInit();
  863.  *
  864.  * Initialize a lot of FPL internal structures and references. Returns
  865.  * NULL if anything went wrong!
  866.  *
  867.  *******/
  868.  
  869. void * ASM fplInit(AREG(0) long (*function) (void *),
  870.            /* function handler pointer */
  871.            AREG(1) unsigned long *tags) /* taglist */
  872. {
  873.   struct Data point;
  874.   struct Data *scr;
  875.   void *init;
  876.   scr=&point;
  877.  
  878. #ifdef AMIGA
  879.   /* Store all register before loading index register */
  880.   StoreRegisters(scr);
  881.   geta4();
  882. #endif
  883.  
  884.   init=Init(&point, function, tags);
  885.   if(!init)
  886.     FREEALLA();
  887. #ifdef DEBUGMAIL
  888.   DebugMail(scr, MAIL_FUNCTION, 500, "fplInit");
  889. #endif
  890.   return(init);
  891. }
  892.  
  893. static void * INLINE Init(struct Data *scr,    /* stack oriented */
  894.               long ASM (*function) (AREG(0) void *), 
  895.               unsigned long *tags) /* taglist */
  896. {
  897.   ReturnCode ret;
  898.   uchar *buffer;
  899.   struct Data *ptr;
  900. #ifdef AMIGA
  901.   long registers[11];
  902.  
  903.   memcpy(registers, scr->registers, sizeof(long)*11);
  904. #endif
  905.   /* Set default that just might get changed in SetTags(); */
  906.  
  907.   memset(scr, 0, sizeof(struct Data)); /* NULLs everything! */
  908.  
  909.   scr->Alloc=DefaultAlloc;
  910.   scr->Dealloc=DefaultDealloc;;
  911.   scr->hash_size=FPL_HASH_SIZE;
  912.   scr->runs=0;
  913.   InitFree(scr); /* init memory caches */
  914.  
  915. #ifdef AMIGA
  916.  
  917.   memcpy(scr->registers, registers, sizeof(long)*11);
  918.  
  919.   scr->stack_size=FPL_MIN_STACK;
  920.   scr->stack_max=FPL_MAX_STACK;
  921.   scr->stack_limit=FPL_MAX_LIMIT;
  922.   scr->stack_margin=FPLSTACK_MINIMUM;
  923. #endif
  924.  
  925.   SetTags(scr, tags); /* read tags and set proper members */
  926.  
  927.   buffer=(uchar *)MALLOCA(BUF_SIZE);
  928.   if(!buffer)
  929.     /* fail! */
  930.     return(NULL);
  931.  
  932. #ifdef AMIGA
  933. #pragma msg 225 ignore    /* ignore the 225 warnings that occur on the following
  934.                assign! */
  935. #endif
  936.   scr->function=(long ASM (*)(AREG(0) void *))function;
  937.  
  938. #ifdef AMIGA
  939. #pragma msg 225 warning    /* enable the 225 warnings again! */
  940. #endif
  941.  
  942.   scr->buf=buffer;
  943.  
  944. #if defined(AMIGA) && defined(SHARED)
  945.   scr->stack_base=MALLOCA(scr->stack_size);
  946.   if(!scr->stack_base)
  947.     return(NULL);
  948.   scr->intern_stack = (long)scr->stack_base + scr->stack_size;
  949.   Forbid();
  950.   scr->task = FindTask(NULL);  /* get pointer to our task! */
  951.   Permit();
  952. #endif
  953.  
  954.   if(ret=InitHash(scr))
  955.     return(NULL);
  956.  
  957.   ptr=(struct Data *)MALLOCA(sizeof(struct Data));
  958.   if(ptr)
  959.     *ptr=*scr; /* copy the entire structure! */
  960.  
  961.   return((void *)ptr);
  962. }
  963.  
  964. #ifndef AMIGA /* if not using SAS/C on Amiga */
  965.  
  966. #ifdef VARARG_FUNCTIONS
  967. long fplResetTags(void *anchor, ...)
  968. {
  969.   va_list tags;
  970.   long ret;
  971.   va_start(tags, anchor); /* get parameter list */
  972.   ret = fplReset(anchor, (unsigned long *)tags);
  973.   va_end(tags)
  974.   return ret;
  975. }
  976. #else
  977. long fplResetTags(void *anchor, unsigned long tags, ...)
  978. {
  979.   return(fplReset(anchor, &tags));
  980. }
  981. #endif
  982.  
  983. #endif
  984.  
  985. /**********************************************************************
  986.  *
  987.  * fplReset();
  988.  *
  989.  * This function is used to change or add tags to FPL. All tags
  990.  * available for fplFree() is legal. Not changed tags will remain
  991.  * as they were before this call!
  992.  *
  993.  * I had to insert this function since I found out that I wanted to
  994.  * alter the userdata in my application using FPL, and that was hard
  995.  * doing so (nice) without this change.
  996.  * 
  997.  * Library front end to SetTags();
  998.  *
  999.  *****/
  1000.  
  1001. ReturnCode PREFIX fplReset(AREG(0) struct Data *scr,
  1002.                 AREG(1) unsigned long *tags)
  1003. {
  1004. #ifdef DEBUGMAIL
  1005.   DebugMail(scr, MAIL_FUNCTION, 500, "fplReset");
  1006. #endif
  1007.   if(!scr)
  1008.     return FPLERR_ILLEGAL_ANCHOR;
  1009.   return SetTags(scr, tags);
  1010. }
  1011.  
  1012.  
  1013. /**********************************************************************
  1014.  *
  1015.  * SetTags();
  1016.  *
  1017.  * Read the taglist supplied in the second parameter, and set all data
  1018.  * according to those.
  1019.  *
  1020.  *****/
  1021.  
  1022. static ReturnCode REGARGS
  1023. SetTags(struct Data *scr,
  1024.         unsigned long *tags)
  1025. {
  1026.   if(!scr)
  1027.     return(FPLERR_ILLEGAL_ANCHOR);
  1028.  
  1029.   while(tags && *tags) {
  1030.     switch(*tags++) {
  1031. #ifdef AMIGA
  1032. #pragma msg 225 ignore    /* ignore the 225 warnings that occur on the following
  1033.                four assigns! */
  1034. #endif
  1035.     case FPLTAG_INTERVAL:
  1036.       scr->interfunc=(long ASM (*)(AREG(0) void *))*tags;
  1037.       break;
  1038.  
  1039.     case FPLTAG_INTERNAL_ALLOC:
  1040.       scr->Alloc=(void * ASM (*)(DREG(0) long,
  1041.                                  AREG(0) void *))*tags;
  1042.       break;
  1043.     case FPLTAG_INTERNAL_DEALLOC:
  1044.       scr->Dealloc=(void ASM (*)(AREG(1) void *,
  1045.                                  DREG(0) long,
  1046.                                  AREG(0) void *))*tags;
  1047.       break;
  1048. #ifdef AMIGA
  1049. #pragma msg 225 warning /* enable the 225 warning again for correct program
  1050.                checking! */
  1051. #endif
  1052.  
  1053.     case FPLTAG_REREAD_CHANGES:
  1054.       scr->flags = BitToggle(scr->flags, FPLDATA_REREAD_CHANGES, *tags);
  1055.       break;
  1056.  
  1057.     case FPLTAG_FLUSH_NOT_IN_USE:
  1058.       scr->flags = BitToggle(scr->flags, FPLDATA_FLUSH_NOT_IN_USE, *tags);
  1059.       break;
  1060.  
  1061.     case FPLTAG_KIDNAP_CACHED:
  1062.       scr->flags = BitToggle(scr->flags, FPLDATA_KIDNAP_CACHED, *tags);
  1063.       break;
  1064.  
  1065.     case FPLTAG_PREVENT_RUNNING_SAME:
  1066.       scr->flags = BitToggle(scr->flags, FPLDATA_PREVENT_RUNNING_SAME, *tags);
  1067.       break;
  1068.  
  1069.     case FPLTAG_HASH_TABLE_SIZE:
  1070.       if(*tags>FPL_MIN_HASH)
  1071.     scr->hash_size=*tags;
  1072.       break;
  1073.  
  1074.     case FPLTAG_USERDATA:
  1075.       scr->userdata=(void *)*tags;
  1076.       break;
  1077.  
  1078.     case FPLTAG_ALLFUNCTIONS:
  1079.       scr->flags = BitToggle(scr->flags, FPLDATA_ALLFUNCTIONS, *tags);
  1080.       break;
  1081.  
  1082.     case FPLTAG_NESTED_COMMENTS:
  1083.       scr->flags = BitToggle(scr->flags, FPLDATA_NESTED_COMMENTS, *tags);
  1084.       break;
  1085.  
  1086.     case FPLTAG_CACHEALLFILES:
  1087.       if(*tags) {
  1088.     scr->flags|=FPLDATA_CACHEALLFILES;
  1089.     if(*tags == FPLCACHE_EXPORTS)
  1090.       scr->flags|=FPLDATA_CACHEEXPORTS;
  1091.       } else
  1092.     scr->flags &= ~(FPLDATA_CACHEALLFILES|FPLDATA_CACHEEXPORTS);
  1093.       break;
  1094.  
  1095. #ifdef STRING_STACK
  1096.     case FPLTAG_STRINGSTACK:
  1097.       scr->strings_in_stack_max = (long)*tags;
  1098.       if( scr->strings_in_stack_max>0 ) {
  1099.         if(scr->stringsstack) {
  1100.           FREEA(scr->stringsstack);
  1101.         }
  1102.         GETMEMA(scr->stringstack, scr->strings_in_stack_max *
  1103.                                   sizeof( struct StringStack ));
  1104.       }
  1105.       break;
  1106. #endif
  1107.  
  1108. #ifdef AMIGA
  1109.     case FPLTAG_STACK:
  1110.       /* Only change stack if the required size is large enough! */
  1111.       if(*tags>FPL_MIN_STACK)
  1112.     scr->stack_size=(long)*tags;
  1113.       break;
  1114.  
  1115.     case FPLTAG_MAXSTACK:
  1116.       /* Only change this if the required size is large enough! */
  1117.       if(*tags>FPL_MIN_STACK)
  1118.     scr->stack_max=(long)*tags;
  1119.       break;
  1120.  
  1121.     case FPLTAG_STACKLIMIT:
  1122.       /* Only change this if the required size is large enough! */
  1123.       if(*tags>FPL_MIN_STACK)
  1124.     scr->stack_limit=(long)*tags;      
  1125.       break;
  1126.  
  1127.     case FPLTAG_MINSTACK:
  1128.       /* Only change this if the required size is larger than default! */
  1129.       if(*tags>FPLSTACK_MINIMUM)
  1130.     scr->stack_margin=*tags;
  1131.       break;
  1132. #endif
  1133.  
  1134.     case FPLTAG_IDENTITY:
  1135.       /* new from version 9: Host process identifier! */
  1136.       scr->identifier = (uchar *)(*tags);
  1137.       break;
  1138.       
  1139.     case FPLTAG_DEBUG:
  1140.       scr->flags = BitToggle(scr->flags, FPLDATA_DEBUG_GLOBAL, *tags);
  1141.       break;
  1142.       
  1143.     case FPLTAG_ERROR_BUFFER:
  1144.       scr->error = (uchar *)(*tags);
  1145.       break;
  1146.  
  1147.     }
  1148.     tags++; /* next! */
  1149.   }
  1150.   return(FPL_OK);
  1151. }
  1152.  
  1153. long REGARGS
  1154. BitToggle(long original, /* Original 32 bits */
  1155.       long bit,      /* alternate bit pattern */
  1156.       long OnOff)    /* Or/And boolean, TRUE==OR, FALSE==AND */
  1157. {
  1158.   if(OnOff)
  1159.     return ( original | bit );
  1160.   else
  1161.     return ( original & ~bit );
  1162. }
  1163.